package config

import (
	"os"
	"path/filepath"
	"reflect"
	"slapp3/backend/logger"
	"sync"

	"github.com/spf13/viper"
	"go.uber.org/zap"
)

var (
	instance *Config
	once     sync.Once
)

// NewConfig 初始化配置系统
func NewConfig() *Config {
	once.Do(func() {
		v := viper.New()

		// 设置默认值
		cfg := &Config{}
		setDefaultsFromStruct(v, cfg)

		// 默认配置文件路径
		exe, err := os.Executable()
		if err != nil {
			logger.Fatal("获取可执行文件路径失败", zap.Error(err))
		}

		appDir := filepath.Dir(exe)
		v.AddConfigPath(filepath.Join(appDir, "configs"))
		v.AddConfigPath(".")
		v.AddConfigPath("./configs")
		v.AddConfigPath("${HOME}/.config/slapp")

		v.SetConfigName("slapp3_config") // 配置文件名（不带扩展名）
		v.SetConfigType("toml")          // 配置文件类型

		// 读取配置
		if err := v.ReadInConfig(); err != nil {
			if _, ok := err.(viper.ConfigFileNotFoundError); ok {
				logger.Warn("未找到配置文件，使用默认值")
			} else {
				logger.Fatal("读取配置文件失败", zap.Error(err))
			}
		}
		logger.Info("配置文件加载成功", zap.String("path", v.ConfigFileUsed()))
		if err := v.Unmarshal(&cfg); err != nil {
			logger.Fatal("解析配置文件失败", zap.Error(err))
		}
		// 环境变量覆盖
		v.AutomaticEnv()
		instance = cfg
	})

	return instance
}

func setDefaultsFromStruct(v *viper.Viper, cfg interface{}) {
	typ := reflect.TypeOf(cfg).Elem() // 获取结构体类型
	val := reflect.ValueOf(cfg).Elem()

	var traverse func(reflect.Value, reflect.Type, string)
	traverse = func(vVal reflect.Value, vType reflect.Type, prefix string) {
		for i := 0; i < vType.NumField(); i++ {
			field := vType.Field(i)
			fieldVal := vVal.Field(i)

			// 处理嵌套结构体
			if fieldVal.Kind() == reflect.Struct {
				newPrefix := prefix + field.Name + "."
				traverse(fieldVal, field.Type, newPrefix)
				continue
			}

			// 获取 mapstructure 标签名
			tag := field.Tag.Get("mapstructure")
			if tag == "" || tag == "-" {
				continue
			}

			// 获取 default 标签值
			defVal := field.Tag.Get("default")
			if defVal == "" {
				continue
			}

			// 完整键名（处理嵌套）
			key := prefix + tag

			// 为 Viper 设置默认值
			v.SetDefault(key, defVal)
		}
	}

	traverse(val, typ, "")
}
